﻿using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using ICSharpCode.NRefactory.CSharp;
using Xunit;

namespace Framework.Tests.Refactoring.Substitution
{
    public class NonPrivateFieldToPropertyRefactoring : DepthFirstAstVisitor
    {
        public override void VisitFieldDeclaration(FieldDeclaration field)
        {
            if (!field.HasModifier(Modifiers.Private))
            {
                Console.WriteLine(field.Variables.First().Name);

                var propertyDeclaration = new PropertyDeclaration
                    {
                        Name = field.Variables.First().Name,
                        Modifiers = GetPropertyModifiers(field.Modifiers),
                        Setter = GetSetter(field.Modifiers),
                        Getter = new Accessor(),
                        ReturnType = field.ReturnType.Clone()
                    };

                propertyDeclaration.Modifiers |= Modifiers.Virtual;

                field.ReplaceWith(propertyDeclaration);
            }

            base.VisitFieldDeclaration(field);
        }

        private static Modifiers GetPropertyModifiers(Modifiers modifiers)
        {
            if (modifiers.HasFlag(Modifiers.Protected | Modifiers.Internal))
            {
                return Modifiers.Protected;
            }

            return Modifiers.Public;
        }

        private static Accessor GetSetter(Modifiers modifiers)
        {
            var accessor = new Accessor();

            if (modifiers.HasFlag(Modifiers.Readonly))
            {
                accessor.Modifiers = Modifiers.Protected;
            }

            return accessor;
        }
    }

    //Added
    //[Serializable]
    public class Dependency
    {
        public void JustDoIt()
        {

        }
    }

    [Serializable]
    public class PocoWithDependency
    {
        //Added
        [NonSerialized]
        // ReSharper disable UnassignedReadonlyField.Compiler
        private readonly Dependency dependency;
        // ReSharper restore UnassignedReadonlyField.Compiler

        public PocoWithDependency()
        {
            //this.dependency = dependency;
        }

        public string Name { get; set; }

        public void DoAnything()
        {
            dependency.JustDoIt();
        }
    }

    public class PocoDetectorTest
    {
        [Fact]
        public void Should_test_serializable_convention()
        {
            var binaryFormatter = new BinaryFormatter();

            using (var stream = new MemoryStream())
            {
                binaryFormatter.Serialize(stream, new PocoWithDependency());

                stream.Seek(0, SeekOrigin.Begin);

                var result = (PocoWithDependency)binaryFormatter.Deserialize(stream);

                Assert.NotNull(result);
            }
        }
    }


    public class ClassForDomainOld
    {
        protected readonly string Protected;
        protected internal string ProtectedInternal;
        internal string Internal;
        private string Private;
        public string Public;
        public string PublicProperty { get; set; }
    }

    [Serializable]
    public class ClassForDomain
    {
        public virtual string Protected
        {
            set;
            get;
        }
        public virtual string ProtectedInternal
        {
            set;
            get;
        }
        public virtual string Internal
        {
            set;
            get;
        }
        private string Private;
        public virtual string Public
        {
            set;
            get;
        }
        public string PublicProperty
        {
            get;
            set;
        }
    }

    public class NonPrivateFieldToPropertyRefactoringTest
    {
        [Fact]
        public void Should_make_poc_with_nrefactory()
        {
            var parser = new CSharpParser();

            var syntaxTree = parser.Parse(@"
    public class ClassForDomain
    {
        protected readonly string Protected;
        protected internal string ProtectedInternal;
        internal string Internal;
        private string Private;
        public string Public;
        public string PublicProperty { get; set; }
    }
");

            syntaxTree.AcceptVisitor(new NonPrivateFieldToPropertyRefactoring());

            Console.WriteLine(syntaxTree.GetText());
        }
    }
}
